#include "minicon.h"
#include "miniopt.h"
#include <rpc.h>

extern int err_ret(int errcode, const char *msg, const WCHAR *name);

static void puuid( UUID *puuid, char *ss, int of, bool ucase )
{
   static char xf[5] = "%0??";
   const char *dpref = "", *dsuff = "", *gsuff = "-", *g4pref = "", *g4suff = "";
   int d4 = 2;
   if ( of == '{' || of == '\0' ) {
      dpref = "0x"; dsuff = ","; gsuff = " "; if (of) { g4pref = "{"; g4suff = "}"; } 
      d4 = 0;
   }
   const char* xX = ucase ? "XX" : (of >= 'A' && of <= 'Z') ? "Xx" : "xx";

   xf[2] = '8'; xf[3] = xX[0];
   int nb = ::wsprintfA(ss, "%s", dpref);
   nb += wsprintfA(ss+nb, xf, puuid->Data1);
   nb += ::wsprintfA(ss+nb, "%s%s%s", dsuff, gsuff, dpref);
   xf[2] = '4';
   nb += wsprintfA(ss+nb, xf, (DWORD)puuid->Data2);
   nb += ::wsprintfA(ss+nb, "%s%s%s", dsuff, gsuff, dpref);
   xf[3] = xX[1];
   nb += wsprintfA(ss+nb, xf, (DWORD)puuid->Data3);
   nb += ::wsprintfA(ss+nb, "%s%s", dsuff, gsuff);
   xf[2] = '2'; xf[3] = xX[0];
   if ( d4 == 2 ) {
      nb += ::wsprintfA(ss+nb, xf, (DWORD)puuid->Data4[0]);
      nb += ::wsprintfA(ss+nb, xf, (DWORD)puuid->Data4[1]);
      nb += ::wsprintfA(ss+nb, "%s", gsuff);
   }
   nb += ::wsprintfA(ss+nb, "%s", g4pref);
   while ( d4 < 8 ) {
      nb += ::wsprintfA(ss+nb, "%s", dpref);
      nb += ::wsprintfA(ss+nb, xf, (DWORD)puuid->Data4[d4++]);
      nb += ::wsprintfA(ss+nb, "%s", d4 < 8 ? dsuff : "");
   }
   ::wsprintfA(ss+nb, "%s", g4suff);
}

int uuidgen( bool seq, unsigned n, int of, bool ucase )
{
   int rc = 0; unsigned i; UUID uuid; char ss[80];
   union {
      FARPROC f;
      RPC_STATUS (RPC_ENTRY *UuidCreate) (OUT UUID __RPC_FAR * Uuid);
      RPC_STATUS (RPC_ENTRY *UuidCreateSequential) (OUT UUID __RPC_FAR * Uuid);
   } u;

   u.f = NULL;
   if ( Win::hrpc ) u.f = ::GetProcAddress(Win::hrpc, seq ? "UuidCreateSequential" : "UuidCreate");
   if ( !u.f )
   {
      rc = err_ret(-21, "Can't load UUID creation function from rpcrt4.dll", NULL); goto e;
   }

   for (i = 0; i < n; ++i )
   {
      RPC_STATUS rs = u.UuidCreate(&uuid); // really UuidCreateSequential() can be there...
      if ( rs != RPC_S_OK && rs != RPC_S_UUID_LOCAL_ONLY )
      {
         rc = err_ret(-22, "UUID creation error", NULL); goto e;
      }
      puuid(&uuid, ss, of, ucase);
      switch (of) {
         case 'i':
            Con::f("[\r\nuuid(%s),\r\nversion(1.0)\r\n]\r\ninterface INTERFACENAME\r\n{\r\n\r\n}\r\n", ss);
         break;
         case 's':
            Con::f("INTERFACENAME = /* %s */\r\n", ss);
            puuid(&uuid, ss, '{', ucase);
            Con::f("{ %s };\r\n", ss);
         break;
         case 'I':
            Con::f("// {%s}\r\nIMPLEMENT_OLECREATE(<<class>>, <<external_name>>,\r\n", ss); 
            puuid(&uuid, ss, '\0', ucase);
            Con::f("%s);\r\n", ss);
         break;
         case 'S':
            Con::f("// {%s}\r\nstatic const GUID <<name>> =\r\n", ss);
            puuid(&uuid, ss, '{', ucase);
            Con::f("{ %s };\r\n", ss);
         break;       
         case 'D': case 'd':
            Con::f("// {%s}\r\nDEFINE_GUID(<<name>>,\r\n", ss);
            puuid(&uuid, ss, '\0', ucase);
            Con::f("%s);\r\n", ss);
         break;
         case 'R': case 'r':
            Con::f("{%s}\r\n", ss);
         break;
         default: // '0'
            Con::f("%s\r\n", ss);
         break;
      }
   }

e: return rc;
}
